home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / CodeTextView.C < prev    next >
C/C++ Source or Header  |  1992-08-24  |  10KB  |  482 lines

  1. #ifdef __GNUG__
  2. #pragma implementation
  3. #endif
  4.  
  5. #include "CodeTextView.h"
  6.  
  7. #include "Class.h"
  8. #include "StyledText.h"
  9. #include "RunArray.h"
  10. #include "Env.h"
  11. #include "Math.h"
  12.  
  13. static char *match     = "lass",
  14.         *obrackets = "({[\"",
  15.         *cbrackets = ")}]\"";
  16.  
  17. //---- CodeTextView ------------------------------------------------------------
  18.  
  19. NewMetaImpl(CodeTextView,TextView, (TB(autoIndent), T(cursorPos)));
  20.  
  21. CodeTextView::CodeTextView(
  22.     EvtHandler *eh, Rectangle r, Text *t, 
  23.     bool w, TextViewFlags f, Point b, 
  24.     TViewAlign ta, int id
  25. ) : TextView(eh, r, t, w, f, b, ta, id) 
  26. {
  27.     SetStopChars("\n\r");
  28.     autoIndent= TRUE;
  29.     SetupStyles(t->GetFont());
  30.     ExitCursorMode();
  31. }   
  32.  
  33. Command *CodeTextView::DoKeyCommand(int ch, Token token)
  34. {
  35.     Command *cmd;
  36.  
  37.     ExitCursorMode();
  38.     if ((ch == '\r' || ch == '\n') && autoIndent) { // auto indent
  39.     int from, to, i;
  40.     Text *t= GetText();
  41.     GetSelection(&from, &to);
  42.     scratchText->Empty();
  43.     scratchText->Append('\n'); 
  44.     for (i= StartLine(CharToLine(from)); i < t->End(); i++) {
  45.         ch= (*t)[i];
  46.         if (ch == ' ' || ch == '\t')
  47.         scratchText->Append(ch);
  48.         else
  49.         break;
  50.     }
  51.     cmd= InsertText(scratchText);
  52.     scratchText->Empty();
  53.     RevealSelection();
  54.     return cmd;
  55.     }
  56.     return TextView::DoKeyCommand(ch, token);
  57. }
  58.  
  59. void CodeTextView::SetFont(Font *fp)
  60. {
  61.     SetupStyles(fp);
  62.     TextView::SetFont(fp);
  63. }
  64.  
  65. void CodeTextView::SetupStyles(Font *fp)
  66. {
  67.     int declsize= fp->Size()
  68.           + Env::GetValue("CodeText.DeclarationSizeIncrement", 2);
  69.           
  70.     commentStyle= new_CharStyle(
  71.     new_Font(fp->Fid(), fp->Size(), eFaceItalic)
  72.     );
  73.     functionStyle= new_CharStyle(
  74.     new_Font(fp->Fid(), declsize, eFaceBold)
  75.     );
  76.     classDeclStyle= new_CharStyle(
  77.     new_Font(fp->Fid(), declsize, eFaceBold)
  78.     );
  79.     plainStyle= new_CharStyle(
  80.     new_Font(fp->Fid(), fp->Size(), eFacePlain)
  81.     );
  82. }
  83.  
  84. void CodeTextView::SetAutoIndent(bool b)
  85. {
  86.     autoIndent= b;
  87. }
  88.     
  89. bool CodeTextView::GetAutoIndent()
  90. {
  91.     return autoIndent;
  92. }
  93.  
  94. void CodeTextView::ExitCursorMode()
  95. {
  96.     cursorPos= gPoint_1;
  97. }
  98.  
  99. Command *CodeTextView::DoLeftButtonDownCommand(Point p, Token t, int cl)
  100. {
  101.     Point sp= p;
  102.     ExitCursorMode();
  103.     if (!Enabled())
  104.     return gNoChanges;
  105.     if (cl >= 2) {
  106.     int line, cpos;
  107.     char *br;
  108.     Point pp;
  109.     Text *text= GetText();
  110.  
  111.     p-= GetInnerOrigin();
  112.     PointToPoint(p, &pp, &line, &cpos);
  113.     
  114.     if (cpos > 0 && (br= strchr(obrackets,(*text)[cpos-1]))) {
  115.         MatchBracketForward(cpos, *br, cbrackets[br-obrackets]);
  116.         return gNoChanges;
  117.     }
  118.     if (cpos < text->End() && (br= strchr(cbrackets,(*text)[cpos]))) {
  119.         MatchBracketBackward(cpos-1, obrackets[br-cbrackets], *br);
  120.         return gNoChanges;
  121.     }
  122.     }
  123.     return TextView::DoLeftButtonDownCommand(sp, t, cl);
  124. }
  125.  
  126. Command *CodeTextView::DoMenuCommand(int m)
  127. {
  128.     ExitCursorMode();
  129.     return TextView::DoMenuCommand(m);
  130. }
  131.     
  132. Command *CodeTextView::DoOtherEventCommand(Point p, Token t)
  133. {
  134.     ExitCursorMode();
  135.     return TextView::DoOtherEventCommand(p, t);
  136. }
  137.  
  138. void CodeTextView::MatchBracketForward(int from, int obracket, int cbracket)
  139. {
  140.     Text *text= GetText();
  141.     int ch, stack= 0;
  142.  
  143.     for (int i= from; i < text->End(); i++) {
  144.     ch= (*text)[i];
  145.     if (ch == cbracket) {
  146.         if (stack-- == 0) 
  147.         break;
  148.     } else if (ch == obracket)
  149.         stack++;
  150.     }    
  151.     SetSelection(from, i, TRUE);
  152. }
  153.  
  154. void CodeTextView::MatchBracketBackward(int from, int obracket, int cbracket)
  155. {
  156.     Text *text= GetText();
  157.     int ch, stack= 0;
  158.  
  159.     for (int i= from; i >= 0; i--) {
  160.     ch= (*text)[i];
  161.     if (ch == obracket) { 
  162.         if (stack-- == 0) 
  163.         break;
  164.     } else if (ch == cbracket)
  165.         stack++;
  166.     }
  167.     SetSelection(i+1, from+1, TRUE);
  168. }
  169.  
  170. Command *CodeTextView::DoCursorKeyCommand(EvtCursorDir cd, Token t)
  171. {
  172.     if (cd == eCrsLeft || cd == eCrsRight)
  173.     ExitCursorMode();
  174.     return TextView::DoCursorKeyCommand(cd, t);
  175. }
  176.  
  177. int CodeTextView::CursorPos(int at, int line, EvtCursorDir d, Point p)
  178. {    
  179.     int charNo;
  180.     Point basePoint;
  181.     
  182.     if (cursorPos == gPoint_1) 
  183.     CharToPoint(at, &line, &cursorPos);
  184.  
  185.     if (d == eCrsDown)
  186.     line= Math::Min(nLines-1, line+1);
  187.     else
  188.     line= Math::Max(0, line-1);        
  189.     basePoint= LineToPoint(line, TRUE) + Point(cursorPos.x, 0);
  190.     PointToPoint(basePoint, &p, &line, &charNo);
  191.     return charNo;
  192. }
  193.  
  194. PrettyPrinter *CodeTextView::MakePrettyPrinter(
  195.     Text *t, CharStyle *cs, CharStyle *fs, CharStyle *cds, CharStyle *ps
  196. {
  197.     return new PrettyPrinter(t, cs, fs, cds, ps);
  198. }
  199.  
  200. void CodeTextView::FormatCode()
  201. {
  202.     if (!text->IsKindOf(StyledText)) 
  203.     return;
  204.     PrettyPrinter *pp= MakePrettyPrinter(
  205.     text, commentStyle, functionStyle, classDeclStyle, plainStyle
  206.     );
  207.     pp->Doit();
  208.     SafeDelete(pp);
  209. }
  210.  
  211. void CodeTextView::SetDefaultStyle()
  212. {
  213.     if (!text->IsKindOf(StyledText)) 
  214.     return;
  215.     StyledText *stext= (StyledText*)text;
  216.     RunArray *st= new RunArray();
  217.     st->Insert(plainStyle, 0, 0, stext->Size());
  218.     RunArray *tmpp= stext->SetCharStyles(st);
  219.     delete tmpp;
  220. }
  221.  
  222. //---- CodeAnalyzer ----------------------------------------------------------
  223.  
  224. CodeAnalyzer::CodeAnalyzer(Text *t)
  225. {
  226.     text= t;
  227. }
  228.  
  229. void CodeAnalyzer::Doit()
  230. {
  231.     inDefine= escape= inClass= FALSE;
  232.     lastComment= prevCh= braceStack= inString= line= 0;
  233.     c= '\n'; 
  234.     int canBeClass= canBeFunction= -1;
  235.  
  236.     AutoTextIter next(text, 0, text->Size());
  237.     Start();
  238.     
  239.     while ((c= next()) != cEOT) {
  240.     if (escape)
  241.         escape=FALSE;
  242.     else
  243.         switch (c) {
  244.         case '#':
  245.         if (prevCh == '\n')
  246.             inDefine= TRUE;
  247.         break;
  248.         case '\\':
  249.         escape= TRUE;
  250.         break;
  251.         case '\n':
  252.         inDefine= FALSE;
  253.         line++;
  254.         break;
  255.         case '*':
  256.         if (prevCh == '/' && inString == 0) {
  257.             if (canBeFunction == -1 && canBeClass == -1)
  258.             lastComment= next->GetPos(); 
  259.             FoundComment(&next);
  260.             prevCh= 0;
  261.             continue;
  262.         }
  263.         break;
  264.         case '/':
  265.         if (prevCh == '/' && inString == 0) {
  266.             if (canBeFunction == -1 && canBeClass == -1)
  267.             lastComment= next->GetPos(); 
  268.             FoundEndOfLineComment(&next);
  269.             prevCh= 0;
  270.             continue;
  271.         }
  272.         break;
  273.         case ';':
  274.         canBeFunction= canBeClass= -1;
  275.         break;
  276.         case '{':
  277.         if (canBeFunction != -1) {
  278.             FoundFunctionOrMethod(canBeFunction, lastComment);
  279.             canBeFunction= -1;
  280.         }
  281.         if (canBeClass != -1) {
  282.             FoundClassDecl(canBeClass);
  283.             canBeClass= -1;
  284.         }
  285.         if (inString == 0)
  286.             braceStack++;
  287.         break;
  288.         case '}':
  289.         if (inString == 0)
  290.             braceStack--;
  291.         break;
  292.         case '(':
  293.         if (!inDefine && inString == 0) {
  294.             if (braceStack == 0 && canBeFunction == -1)
  295.             canBeFunction= next->GetPos()-1;
  296.             braceStack++;
  297.         }
  298.         break;
  299.         case ')':
  300.         if (!inDefine && inString == 0)
  301.             braceStack--;
  302.         break;
  303.         case '\'':
  304.         case '\"':
  305.         if (inString == 0) {
  306.             if (c == '\"')
  307.             inString= '\"';
  308.             else
  309.             inString= '\'';
  310.         } else {
  311.             if ((inString == '\"' && c == '\"') || (inString == '\'' 
  312.                              && c == '\''))
  313.             inString= 0;
  314.         }
  315.         break;
  316.         default:
  317.         if (c == 'c' && !inDefine && inString == 0 
  318.             && !inClass && canBeClass == -1) {
  319.             if (braceStack == 0)
  320.             if (inClass= IsClassDecl(next->GetPos()))
  321.                 next->SetPos(next->GetPos()+4);
  322.         } else if (inClass && Isinword(c)) {
  323.             inClass= FALSE;
  324.             canBeClass= next->GetPos();
  325.         }
  326.         break;
  327.     }
  328.     prevCh= c;
  329.     }
  330.     End();
  331. }
  332.  
  333. void CodeAnalyzer::FoundComment(AutoTextIter *next)
  334. {
  335.     int c, prevCh= 0, l= line, start= (*next)->GetPos()-2;
  336.    
  337.     while ((c= (*next)()) != cEOT) {
  338.     if (c == '\n')
  339.         line++;
  340.     if (c == '/' && prevCh == '*') {
  341.         Comment(l, start, (*next)->GetPos());
  342.         break;
  343.     }
  344.     prevCh= c;
  345.     }
  346. }
  347.  
  348. void CodeAnalyzer::FoundEndOfLineComment(AutoTextIter *next)
  349. {
  350.     int c, start= (*next)->GetPos()-2;
  351.  
  352.     while ((c= (*next)()) != cEOT) 
  353.     if (c == '\n') {
  354.         Comment(line, start, (*next)->GetPos()-1);
  355.         line++;
  356.         break;
  357.     }
  358. }
  359.  
  360. void CodeAnalyzer::FoundFunctionOrMethod(int at, int lastComment)
  361. {
  362.     byte c;
  363.     int pos= at, len= 0;
  364.     while (--pos >= lastComment) {
  365.     c= (*text)[pos];
  366.     if (!Isspace(c) && !strchr("[]*+-=%&><|:^%()~/",c)) // overloaded operators
  367.         break;
  368.     }
  369.     while (pos >= lastComment) {
  370.     c= (*text)[pos];
  371.     if (!(Isinword(c) || c == ':' || c == '~' ))
  372.         break;
  373.     if (pos-1 < 0)
  374.         break;
  375.     pos--;
  376.     len++;
  377.     }
  378.     
  379.     if (len) {
  380.     char buf[500];
  381.     pos++;
  382.     text->CopyInStr((byte*)buf, sizeof buf, pos, pos+len);
  383.     char *p= strchr(buf, ':');
  384.     if (!p)
  385.         Function(line, pos, pos+len, buf, 0);
  386.     else {
  387.         *p= '\0';
  388.         char *pp= p+2;
  389.         Function(line, pos, pos+len, pp, buf);
  390.     }
  391.     }
  392. }
  393.  
  394. bool CodeAnalyzer::IsClassDecl(int at)
  395. {
  396.     char *p= match;
  397.     int c;
  398.     AutoTextIter next(text, at, text->Size());
  399.  
  400.     while ((c= next()) != cEOT && *p)
  401.     if (c != *p++) 
  402.         return FALSE;
  403.     return TRUE;
  404. }
  405.  
  406. void CodeAnalyzer::FoundClassDecl(int at)
  407. {
  408.     int end, c, start= at-1;
  409.     AutoTextIter next(text, start, text->Size());
  410.  
  411.     while ((c= next()) != cEOT) 
  412.     if (!Isinword(c)) 
  413.         break;
  414.     end= next->GetPos()-1;
  415.     if (start != end) {
  416.     static byte name[1000];
  417.     text->CopyInStr(name, sizeof name, start, end);
  418.     ClassDecl(line, start, end, (char*)name);
  419.     }
  420. }
  421.  
  422. void CodeAnalyzer::Start()
  423. {
  424. }
  425.  
  426. void CodeAnalyzer::End()
  427. {
  428. }
  429.  
  430. void CodeAnalyzer::Comment(int, int, int)
  431. {
  432. }
  433.  
  434. void CodeAnalyzer::ClassDecl(int, int, int, char *)
  435. {
  436. }
  437.     
  438. void CodeAnalyzer::Function(int, int, int, char *, char *)
  439. {
  440. }
  441.  
  442. //---- PrettyPrinter ---------------------------------------------------------
  443.  
  444. PrettyPrinter::PrettyPrinter(
  445.     Text *t, CharStyle *cs, CharStyle *fs, CharStyle *cds, CharStyle *ps
  446. ) : CodeAnalyzer(t)
  447. {
  448.     stext= Guard(t, StyledText);
  449.     plainStyle= ps;
  450.     commentStyle= cs;
  451.     classDeclStyle= cds;
  452.     functionStyle= fs;
  453. }
  454.  
  455. void PrettyPrinter::Start()
  456. {
  457.     st= new RunArray();
  458.     st->Insert(plainStyle, 0, 0, stext->Size());
  459. }
  460.  
  461. void PrettyPrinter::End()
  462. {
  463.     RunArray *tmpp= stext->SetCharStyles(st);
  464.     delete tmpp;
  465. }
  466.  
  467. void PrettyPrinter::Comment(int, int start, int end)
  468. {
  469.     st->Insert(commentStyle, start, end, end-start);
  470. }
  471.  
  472. void PrettyPrinter::ClassDecl(int, int start, int end, char *)
  473. {
  474.     st->Insert(classDeclStyle, start, end, end-start);
  475. }
  476.     
  477. void PrettyPrinter::Function(int, int start, int end, char *, char *)
  478. {
  479.     st->Insert(functionStyle, start, end, end-start);
  480. }
  481.